﻿using System;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace Kxzz.Controls
{
    public class MyExtRichTextBox : RichTextBox, IDisposable
    {
        private const uint CFE_AUTOCOLOR = 0x40000000;
        private const uint CFE_BOLD = 1;
        private const uint CFE_ITALIC = 2;
        private const uint CFE_LINK = 0x20;
        private const uint CFE_PROTECTED = 0x10;
        private const uint CFE_STRIKEOUT = 8;
        private const uint CFE_SUBSCRIPT = 0x10000;
        private const uint CFE_SUPERSCRIPT = 0x20000;
        private const uint CFE_UNDERLINE = 4;
        private const int CFM_ALLCAPS = 0x80;
        private const int CFM_ANIMATION = 0x40000;
        private const int CFM_BACKCOLOR = 0x4000000;
        private const uint CFM_BOLD = 1;
        private const uint CFM_CHARSET = 0x8000000;
        private const uint CFM_COLOR = 0x40000000;
        private const int CFM_DISABLED = 0x2000;
        private const int CFM_EMBOSS = 0x800;
        private const uint CFM_FACE = 0x20000000;
        private const int CFM_HIDDEN = 0x100;
        private const int CFM_IMPRINT = 0x1000;
        private const uint CFM_ITALIC = 2;
        private const int CFM_KERNING = 0x100000;
        private const int CFM_LCID = 0x2000000;
        private const uint CFM_LINK = 0x20;
        private const uint CFM_OFFSET = 0x10000000;
        private const int CFM_OUTLINE = 0x200;
        private const uint CFM_PROTECTED = 0x10;
        private const int CFM_REVAUTHOR = 0x8000;
        private const int CFM_REVISED = 0x4000;
        private const int CFM_SHADOW = 0x400;
        private const uint CFM_SIZE = 0x80000000;
        private const int CFM_SMALLCAPS = 0x40;
        private const int CFM_SPACING = 0x200000;
        private const uint CFM_STRIKEOUT = 8;
        private const int CFM_STYLE = 0x80000;
        private const uint CFM_SUBSCRIPT = 0x30000;
        private const uint CFM_SUPERSCRIPT = 0x30000;
        private const uint CFM_UNDERLINE = 4;
        private const int CFM_UNDERLINETYPE = 0x800000;
        private const int CFM_WEIGHT = 0x400000;
        private const byte CFU_UNDERLINE = 1;
        private const byte CFU_UNDERLINEDASH = 5;
        private const byte CFU_UNDERLINEDASHDOT = 6;
        private const byte CFU_UNDERLINEDASHDOTDOT = 7;
        private const byte CFU_UNDERLINEDOTTED = 4;
        private const byte CFU_UNDERLINEDOUBLE = 3;
        private const byte CFU_UNDERLINEHAIRLINE = 10;
        private const byte CFU_UNDERLINENONE = 0;
        private const byte CFU_UNDERLINETHICK = 9;
        private const byte CFU_UNDERLINEWAVE = 8;
        private const byte CFU_UNDERLINEWORD = 2;
        private const int EM_GETCHARFORMAT = 0x43a;
        private const int EM_SETCHARFORMAT = 0x444;
        private const int EM_SETEVENTMASK = 0x431;
        private const string FF_UNKNOWN = "UNKNOWN";
        public gifCollections gifs;
        private RtfColor highlightColor;
        private const int HMM_PER_INCH = 0x9ec;
        protected IntPtr IRichEditOlePtr;
        protected IRichEditOle IRichEditOleValue;
        private const int MM_ANISOTROPIC = 8;
        private const int MM_HIENGLISH = 5;
        private const int MM_HIMETRIC = 3;
        private const int MM_ISOTROPIC = 7;
        private const int MM_LOENGLISH = 4;
        private const int MM_LOMETRIC = 2;
        private const int MM_TEXT = 1;
        private const int MM_TWIPS = 6;
        private Panel panelGif;
        private const string RTF_DOCUMENT_POST = @"\cf0\fs17}";
        private const string RTF_DOCUMENT_PRE = @"\viewkind4\uc1\pard\cf1\f0\fs20";
        private const string RTF_HEADER = @"{\rtf1\ansi\ansicpg1252\deff0\deflang1033";
        private string RTF_IMAGE_POST;
        private HybridDictionary rtfColor;
        private HybridDictionary rtfFontFamily;
        private const int SCF_ALL = 4;
        private const int SCF_SELECTION = 1;
        private const int SCF_WORD = 2;
        private RtfColor textColor;
        private const int TWIPS_PER_INCH = 0x5a0;
        private const int WM_SETREDRAW = 11;
        private const int WM_USER = 0x400;
        private float xDpi;
        private float yDpi;

        public MyExtRichTextBox()
        {
            this.IRichEditOleValue = null;
            this.IRichEditOlePtr = IntPtr.Zero;
            this.RTF_IMAGE_POST = "}";
            this.gifs = new gifCollections();
            this.panelGif = new Panel();
            this.textColor = RtfColor.Black;
            this.highlightColor = RtfColor.White;
            this.rtfColor = new HybridDictionary();
            this.rtfColor.Add(RtfColor.Aqua, @"\red0\green255\blue255");
            this.rtfColor.Add(RtfColor.Black, @"\red0\green0\blue0");
            this.rtfColor.Add(RtfColor.Blue, @"\red0\green0\blue255");
            this.rtfColor.Add(RtfColor.Fuchsia, @"\red255\green0\blue255");
            this.rtfColor.Add(RtfColor.Gray, @"\red128\green128\blue128");
            this.rtfColor.Add(RtfColor.Green, @"\red0\green128\blue0");
            this.rtfColor.Add(RtfColor.Lime, @"\red0\green255\blue0");
            this.rtfColor.Add(RtfColor.Maroon, @"\red128\green0\blue0");
            this.rtfColor.Add(RtfColor.Navy, @"\red0\green0\blue128");
            this.rtfColor.Add(RtfColor.Olive, @"\red128\green128\blue0");
            this.rtfColor.Add(RtfColor.Purple, @"\red128\green0\blue128");
            this.rtfColor.Add(RtfColor.Red, @"\red255\green0\blue0");
            this.rtfColor.Add(RtfColor.Silver, @"\red192\green192\blue192");
            this.rtfColor.Add(RtfColor.Teal, @"\red0\green128\blue128");
            this.rtfColor.Add(RtfColor.White, @"\red255\green255\blue255");
            this.rtfColor.Add(RtfColor.Yellow, @"\red255\green255\blue0");
            this.rtfFontFamily = new HybridDictionary();
            this.rtfFontFamily.Add(FontFamily.GenericMonospace.Name, @"\fmodern");
            this.rtfFontFamily.Add(FontFamily.GenericSansSerif, @"\fswiss");
            this.rtfFontFamily.Add(FontFamily.GenericSerif, @"\froman");
            this.rtfFontFamily.Add("UNKNOWN", @"\fnil");
            using (Graphics _graphics = base.CreateGraphics())
            {
                this.xDpi = _graphics.DpiX;
                this.yDpi = _graphics.DpiY;
            }
        }

        public MyExtRichTextBox(RtfColor _textColor) : this()
        {
            this.textColor = _textColor;
        }

        public MyExtRichTextBox(RtfColor _textColor, RtfColor _highlightColor) : this()
        {
            this.textColor = _textColor;
            this.highlightColor = _highlightColor;
        }

        public MyPicture addGifControl(uint gifID, Image image)
        {
            MyPicture pic = new MyPicture();
            pic.Tag = gifID;
            pic.Image = image;
            pic.SizeMode = PictureBoxSizeMode.AutoSize;
            pic.BackColor = this.BackColor;
            pic.Invalidate();
            this.panelGif.Controls.Add(pic);
            this.gifs.add(pic);
            this.InsertMyControl(pic);
            base.Invalidate();
            return pic;
        }

        public void AppendRtf(string _rtf)
        {
            base.Select(this.TextLength, 0);
            base.SelectedRtf = _rtf;
        }

        public void AppendTextAsRtf(string _text)
        {
            this.AppendTextAsRtf(_text, this.Font);
        }

        public void AppendTextAsRtf(string _text, Font _font)
        {
            this.AppendTextAsRtf(_text, _font, this.textColor);
        }

        public void AppendTextAsRtf(string _text, Font _font, RtfColor _textColor)
        {
            this.AppendTextAsRtf(_text, _font, _textColor, this.highlightColor);
        }

        public void AppendTextAsRtf(string _text, Font _font, RtfColor _textColor, RtfColor _backColor)
        {
            base.Select(this.TextLength, 0);
            this.InsertTextAsRtf(_text, _font, _textColor, _backColor);
        }

        public MyPicture findPic(string ID)
        {
            foreach (MyPicture pic in this.gifs)
            {
                if (Convert.ToString(pic.Tag) == ID)
                {
                    return pic;
                }
            }
            return null;
        }

        private MyPicture findPic(string ID, gifCollections gifs)
        {
            foreach (MyPicture pic in gifs)
            {
                if (Convert.ToString(pic.Tag) == ID)
                {
                    return pic;
                }
            }
            return null;
        }

        [DllImport("gdiplus.dll")]
        private static extern uint GdipEmfToWmfBits(IntPtr _hEmf, uint _bufferSize, byte[] _buffer, int _mappingMode, EmfToWmfBitsFlags _flags);
        [DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
        internal static extern bool GetClientRect(IntPtr hWnd, [In, Out] ref Rectangle rect);
        private string GetColorTable(RtfColor _textColor, RtfColor _backColor)
        {
            StringBuilder _colorTable = new StringBuilder();
            _colorTable.Append(@"{\colortbl ;");
            _colorTable.Append(this.rtfColor[_textColor]);
            _colorTable.Append(";");
            _colorTable.Append(this.rtfColor[_backColor]);
            _colorTable.Append(@";}\n");
            return _colorTable.ToString();
        }

        private string GetDocumentArea(string _text, Font _font)
        {
            StringBuilder _doc = new StringBuilder();
            _doc.Append(@"\viewkind4\uc1\pard\cf1\f0\fs20");
            _doc.Append(@"\highlight2");
            if (_font.Bold)
            {
                _doc.Append(@"\b");
            }
            if (_font.Italic)
            {
                _doc.Append(@"\i");
            }
            if (_font.Strikeout)
            {
                _doc.Append(@"\strike");
            }
            if (_font.Underline)
            {
                _doc.Append(@"\ul");
            }
            _doc.Append(@"\f0");
            _doc.Append(@"\fs");
            _doc.Append((int) Math.Round((double) (2f * _font.SizeInPoints)));
            _doc.Append(" ");
            _doc.Append(_text.Replace("\n", @"\par "));
            _doc.Append(@"\highlight0");
            if (_font.Bold)
            {
                _doc.Append(@"\b0");
            }
            if (_font.Italic)
            {
                _doc.Append(@"\i0");
            }
            if (_font.Strikeout)
            {
                _doc.Append(@"\strike0");
            }
            if (_font.Underline)
            {
                _doc.Append(@"\ulnone");
            }
            _doc.Append(@"\f0");
            _doc.Append(@"\fs20");
            _doc.Append(@"\cf0\fs17}");
            return _doc.ToString();
        }

        public gifCollections GetExistGifs()
        {
            gifCollections tempGifs = new gifCollections();
            REOBJECT reObject = new REOBJECT();
            for (int i = 0; i < this.GetRichEditOleInterface().GetObjectCount(); i++)
            {
                this.GetRichEditOleInterface().GetObject(i, reObject, GETOBJECTOPTIONS.REO_GETOBJ_ALL_INTERFACES);
                MyPicture pic = this.findPic(reObject.dwUser.ToString());
                if (pic != null)
                {
                    pic.pos = reObject.cp;
                    tempGifs.add(pic);
                }
            }
            return tempGifs;
        }

        private string GetFontTable(Font _font)
        {
            StringBuilder _fontTable = new StringBuilder();
            _fontTable.Append(@"{\fonttbl{\f0");
            _fontTable.Append(@"\");
            if (this.rtfFontFamily.Contains(_font.FontFamily.Name))
            {
                _fontTable.Append(this.rtfFontFamily[_font.FontFamily.Name]);
            }
            else
            {
                _fontTable.Append(this.rtfFontFamily["UNKNOWN"]);
            }
            _fontTable.Append(@"\fcharset0 ");
            _fontTable.Append(_font.Name);
            _fontTable.Append(";}}");
            return _fontTable.ToString();
        }

        public string GetImageInfo()
        {
            string imageInfo = "";
            REOBJECT reObject = new REOBJECT();
            for (int i = 0; i < this.GetRichEditOleInterface().GetObjectCount(); i++)
            {
                this.GetRichEditOleInterface().GetObject(i, reObject, GETOBJECTOPTIONS.REO_GETOBJ_ALL_INTERFACES);
                string im = imageInfo;
                imageInfo = im + reObject.cp.ToString() + "," + reObject.dwUser.ToString() + "|";
            }
            return imageInfo;
        }

        private string GetImagePrefix(Image _image)
        {
            StringBuilder _rtf = new StringBuilder();
            int picw = (int) Math.Round((double) ((((float) _image.Width) / this.xDpi) * 2540f));
            int pich = (int) Math.Round((double) ((((float) _image.Height) / this.yDpi) * 2540f));
            int picwgoal = (int) Math.Round((double) ((((float) _image.Width) / this.xDpi) * 1440f));
            int pichgoal = (int) Math.Round((double) ((((float) _image.Height) / this.yDpi) * 1440f));
            _rtf.Append(@"{\pict\wmetafile8");
            _rtf.Append(@"\picw");
            _rtf.Append(picw);
            _rtf.Append(@"\pich");
            _rtf.Append(pich);
            _rtf.Append(@"\picwgoal");
            _rtf.Append(picwgoal);
            _rtf.Append(@"\pichgoal");
            _rtf.Append(pichgoal);
            _rtf.Append(" ");
            return _rtf.ToString();
        }

        [DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
        internal static extern IntPtr GetParent(IntPtr hWnd);
        public IRichEditOle GetRichEditOleInterface()
        {
            if (this.IRichEditOleValue == null)
            {
                IntPtr ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(IntPtr)));
                Marshal.WriteIntPtr(ptr, IntPtr.Zero);
                try
                {
                    try
                    {
                        if (0 == API.SendMessage(base.Handle, 0x43c, IntPtr.Zero, ptr))
                        {
                            throw new Exception("EM_GETOLEINTERFACE failed.");
                        }
                        IntPtr pRichEdit = Marshal.ReadIntPtr(ptr);
                        try
                        {
                            if (!(pRichEdit != IntPtr.Zero))
                            {
                                throw new Exception("Failed to get the pointer.");
                            }
                            Guid guid = new Guid("00020D00-0000-0000-c000-000000000046");
                            Marshal.QueryInterface(pRichEdit, ref guid, out this.IRichEditOlePtr);
                            this.IRichEditOleValue = (IRichEditOle) Marshal.GetTypedObjectForIUnknown(this.IRichEditOlePtr, typeof(IRichEditOle));
                            if (this.IRichEditOleValue == null)
                            {
                                throw new Exception("Failed to get the object wrapper for the interface.");
                            }
                        }
                        finally
                        {
                            Marshal.Release(pRichEdit);
                        }
                    }
                    catch (Exception err)
                    {
                        Trace.WriteLine(err.ToString());
                        this.ReleaseRichEditOleInterface();
                    }
                }
                finally
                {
                    Marshal.FreeCoTaskMem(ptr);
                }
            }
            return this.IRichEditOleValue;
        }

        private string GetRtfImage(Image _image)
        {
            StringBuilder _rtf = null;
            MemoryStream _stream = null;
            Graphics _graphics = null;
            Metafile _metaFile = null;
            string strIms;
            try
            {
                _rtf = new StringBuilder();
                _stream = new MemoryStream();
                using (_graphics = base.CreateGraphics())
                {
                    IntPtr _hdc = _graphics.GetHdc();
                    _metaFile = new Metafile(_stream, _hdc);
                    _graphics.ReleaseHdc(_hdc);
                }
                using (_graphics = Graphics.FromImage(_metaFile))
                {
                    _graphics.DrawImage(_image, new Rectangle(0, 0, _image.Width, _image.Height));
                }
                IntPtr _hEmf = _metaFile.GetHenhmetafile();
                uint _bufferSize = GdipEmfToWmfBits(_hEmf, 0, null, 8, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault);
                byte[] _buffer = new byte[_bufferSize];
                uint _convertedSize = GdipEmfToWmfBits(_hEmf, _bufferSize, _buffer, 8, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault);
                for (int i = 0; i < _buffer.Length; i++)
                {
                    _rtf.Append(string.Format("{0:X2}", _buffer[i]));
                }
                strIms = _rtf.ToString();
            }
            finally
            {
                if (_graphics != null)
                {
                    _graphics.Dispose();
                }
                if (_metaFile != null)
                {
                    _metaFile.Dispose();
                }
                if (_stream != null)
                {
                    _stream.Close();
                }
            }
            return strIms;
        }

        public int GetSelectionLink()
        {
            return this.GetSelectionStyle(0x20, 0x20);
        }

        private int GetSelectionStyle(uint mask, uint effect)
        {
            int state;
            CHARFORMAT2_STRUCT cf = new CHARFORMAT2_STRUCT();
            cf.cbSize = (uint) Marshal.SizeOf(cf);
            cf.szFaceName = new char[0x20];
            IntPtr wpar = new IntPtr(1);
            IntPtr lpar = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf));
            Marshal.StructureToPtr(cf, lpar, false);
            IntPtr res = SendMessage(base.Handle, 0x43a, wpar, lpar);
            cf = (CHARFORMAT2_STRUCT) Marshal.PtrToStructure(lpar, typeof(CHARFORMAT2_STRUCT));
            if ((cf.dwMask & mask) == mask)
            {
                if ((cf.dwEffects & effect) == effect)
                {
                    state = 1;
                }
                else
                {
                    state = 0;
                }
            }
            else
            {
                state = -1;
            }
            Marshal.FreeCoTaskMem(lpar);
            return state;
        }

        [DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
        internal static extern bool GetWindowRect(IntPtr hWnd, [In, Out] ref Rectangle rect);
        public void InsertActiveX(string strProgID)
        {
            System.Type t = System.Type.GetTypeFromProgID(strProgID);
            if (t != null)
            {
                object o = Activator.CreateInstance(t);
                if (o is IOleObject)
                {
                    this.InsertOleObject((IOleObject) o);
                }
            }
        }

        public void InsertImage(Image _image)
        {
            StringBuilder _rtf = new StringBuilder();
            _rtf.Append(@"{\rtf1\ansi\ansicpg1252\deff0\deflang1033");
            _rtf.Append(this.GetFontTable(this.Font));
            _rtf.Append(this.GetImagePrefix(_image));
            _rtf.Append(this.GetRtfImage(_image));
            _rtf.Append(this.RTF_IMAGE_POST);
            base.SelectedRtf = _rtf.ToString();
        }

        public void InsertLink(string text)
        {
            this.InsertLink(text, base.SelectionStart);
        }

        public void InsertLink(string text, int position)
        {
            if ((position < 0) || (position > this.Text.Length))
            {
                throw new ArgumentOutOfRangeException("position");
            }
            base.SelectionStart = position;
            this.SelectedText = text;
            base.Select(position, text.Length);
            this.SetSelectionLink(true);
            base.Select(position + text.Length, 0);
        }

        public void InsertLink(string text, string hyperlink)
        {
            this.InsertLink(text, hyperlink, base.SelectionStart);
        }

        public void InsertLink(string text, string hyperlink, int position)
        {
            if ((position < 0) || (position > this.Text.Length))
            {
                throw new ArgumentOutOfRangeException("position");
            }
            base.SelectionStart = position;
            base.SelectedRtf = @"{\rtf1\ansi\ " + text + @"\v #" + hyperlink + @"\v0}";
            base.Select(position, (text.Length + hyperlink.Length) + 1);
            this.SetSelectionLink(true);
            base.Select(((position + text.Length) + hyperlink.Length) + 1, 0);
        }

        private void InsertMyControl(Control control)
        {
            new RichEditOle(this).InsertControl(control);
        }

        public void InsertMyDataObject(myDataObject mdo)
        {
            new RichEditOle(this).InsertMyDataObject(mdo);
        }

        public void InsertMyImage(Image image)
        {
            myDataObject mdo = new myDataObject();
            mdo.SetImage(image);
            this.InsertMyDataObject(mdo);
        }

        public void InsertMyImage(string imageFile)
        {
            myDataObject mdo = new myDataObject();
            mdo.SetImage(imageFile);
            this.InsertMyDataObject(mdo);
        }

        public void InsertMyImageFromFile(string strFilename)
        {
            new RichEditOle(this).InsertImageFromFile(strFilename);
        }

        public void InsertOleObject(IOleObject oleObj)
        {
            new RichEditOle(this).InsertOleObject(oleObj);
        }

        public void InsertRtf(string _rtf)
        {
            base.SelectedRtf = _rtf;
        }

        public void InsertTextAsRtf(string _text)
        {
            this.InsertTextAsRtf(_text, this.Font);
        }

        public void InsertTextAsRtf(string _text, Font _font)
        {
            this.InsertTextAsRtf(_text, _font, this.textColor);
        }

        public void InsertTextAsRtf(string _text, Font _font, RtfColor _textColor)
        {
            this.InsertTextAsRtf(_text, _font, _textColor, this.highlightColor);
        }

        public void InsertTextAsRtf(string _text, Font _font, RtfColor _textColor, RtfColor _backColor)
        {
            StringBuilder _rtf = new StringBuilder();
            _rtf.Append(@"{\rtf1\ansi\ansicpg1252\deff0\deflang1033");
            _rtf.Append(this.GetFontTable(_font));
            _rtf.Append(this.GetColorTable(_textColor, _backColor));
            _rtf.Append(this.GetDocumentArea(_text, _font));
            base.SelectedRtf = _rtf.ToString();
        }

        [DllImport("ole32.dll")]
        private static extern int OleCreateFromData(IDataObject pSrcDataObj, [In] ref Guid riid, uint renderopt, ref FORMATETC pFormatEtc, IOleClientSite pClientSite, IStorage pStg, [MarshalAs(UnmanagedType.IUnknown)] out object ppvObj);
        [DllImport("ole32.dll")]
        private static extern int OleCreateFromFile([In] ref Guid rclsid, [MarshalAs(UnmanagedType.LPWStr)] string lpszFileName, [In] ref Guid riid, uint renderopt, ref FORMATETC pFormatEtc, IOleClientSite pClientSite, IStorage pStg, [MarshalAs(UnmanagedType.IUnknown)] out object ppvObj);
        [DllImport("ole32.dll")]
        private static extern int OleCreateLinkFromData([MarshalAs(UnmanagedType.Interface)] IDataObject pSrcDataObj, [In] ref Guid riid, uint renderopt, ref FORMATETC pFormatEtc, IOleClientSite pClientSite, IStorage pStg, [MarshalAs(UnmanagedType.IUnknown)] out object ppvObj);
        [DllImport("ole32.dll")]
        private static extern int OleCreateStaticFromData([MarshalAs(UnmanagedType.Interface)] IDataObject pSrcDataObj, [In] ref Guid riid, uint renderopt, ref FORMATETC pFormatEtc, IOleClientSite pClientSite, IStorage pStg, [MarshalAs(UnmanagedType.IUnknown)] out object ppvObj);
        [DllImport("ole32.dll")]
        private static extern int OleLoadPicturePath([MarshalAs(UnmanagedType.LPWStr)] string lpszPicturePath, [In, MarshalAs(UnmanagedType.IUnknown)] object pIUnknown, uint dwReserved, uint clrReserved, ref Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppvObj);
        [DllImport("ole32.dll")]
        private static extern int OleSetContainedObject([MarshalAs(UnmanagedType.IUnknown)] object pUnk, bool fContained);
        private void OnFrameChanged(object sender, EventArgs e)
        {
            this.panelGif.Invalidate();
        }

        public void ReleaseRichEditOleInterface()
        {
            if (this.IRichEditOlePtr != IntPtr.Zero)
            {
                Marshal.Release(this.IRichEditOlePtr);
            }
            this.IRichEditOlePtr = IntPtr.Zero;
            this.IRichEditOleValue = null;
        }

        private string RemoveBadChars(string _originalRtf)
        {
            return _originalRtf.Replace("\0", "");
        }

        [DllImport("User32.dll", CharSet=CharSet.Auto, PreserveSig=false)]
        public static extern IRichEditOle SendMessage(IntPtr hWnd, int message, int wParam);
        [DllImport("user32.dll", CharSet=CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
        [DllImport("user32", CharSet=CharSet.Auto)]
        private static extern int SendMessage(HandleRef hWnd, int msg, int wParam, ref CHARFORMAT lp);
        [DllImport("user32", CharSet=CharSet.Auto)]
        private static extern int SendMessage(HandleRef hWnd, int msg, int wParam, int lParam);
        [DllImport("user32", CharSet=CharSet.Auto)]
        private static extern int SendMessage(HandleRef hWnd, int msg, int wParam, ref PARAFORMAT lp);
        public void SetSelectionLink(bool link)
        {
            uint ui = 0x20;
            if(link)
                ui=0;
            this.SetSelectionStyle(0x20, ui);
        }

        private void SetSelectionStyle(uint mask, uint effect)
        {
            CHARFORMAT2_STRUCT cf = new CHARFORMAT2_STRUCT();
            cf.cbSize = (uint) Marshal.SizeOf(cf);
            cf.dwMask = mask;
            cf.dwEffects = effect;
            IntPtr wpar = new IntPtr(1);
            IntPtr lpar = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf));
            Marshal.StructureToPtr(cf, lpar, false);
            IntPtr res = SendMessage(base.Handle, 0x444, wpar, lpar);
            Marshal.FreeCoTaskMem(lpar);
        }

        public void UpdateObjects()
        {
            new RichEditOle(this).UpdateObjects();
        }

        public RtfColor HiglightColor
        {
            get
            {
                return this.highlightColor;
            }
            set
            {
                this.highlightColor = value;
            }
        }

        public string Rtf
        {
            get
            {
                return this.RemoveBadChars(base.Rtf);
            }
            set
            {
                base.Rtf = value;
            }
        }

        public RtfColor TextColor
        {
            get
            {
                return this.textColor;
            }
            set
            {
                this.textColor = value;
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CHARFORMAT
        {
            public int cbSize;
            public uint dwMask;
            public uint dwEffects;
            public int yHeight;
            public int yOffset;
            public int crTextColor;
            public byte bCharSet;
            public byte bPitchAndFamily;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst=0x20)]
            public char[] szFaceName;
            public short wWeight;
            public short sSpacing;
            public int crBackColor;
            public uint lcid;
            public uint dwReserved;
            public short sStyle;
            public short wKerning;
            public byte bUnderlineType;
            public byte bAnimation;
            public byte bRevAuthor;
            public byte bReserved1;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct CHARFORMAT2_STRUCT
        {
            public uint cbSize;
            public uint dwMask;
            public uint dwEffects;
            public int yHeight;
            public int yOffset;
            public int crTextColor;
            public byte bCharSet;
            public byte bPitchAndFamily;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst=0x20)]
            public char[] szFaceName;
            public ushort wWeight;
            public ushort sSpacing;
            public int crBackColor;
            public int lcid;
            public int dwReserved;
            public short sStyle;
            public short wKerning;
            public byte bUnderlineType;
            public byte bAnimation;
            public byte bRevAuthor;
            public byte bReserved1;
        }

        private enum EmfToWmfBitsFlags
        {
            EmfToWmfBitsFlagsDefault = 0,
            EmfToWmfBitsFlagsEmbedEmf = 1,
            EmfToWmfBitsFlagsIncludePlaceable = 2,
            EmfToWmfBitsFlagsNoXORClip = 4
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct PARAFORMAT
        {
            public int cbSize;
            public uint dwMask;
            public short wNumbering;
            public short wReserved;
            public int dxStartIndent;
            public int dxRightIndent;
            public int dxOffset;
            public short wAlignment;
            public short cTabCount;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst=0x20)]
            public int[] rgxTabs;
            public int dySpaceBefore;
            public int dySpaceAfter;
            public int dyLineSpacing;
            public short sStyle;
            public byte bLineSpacingRule;
            public byte bOutlineLevel;
            public short wShadingWeight;
            public short wShadingStyle;
            public short wNumberingStart;
            public short wNumberingStyle;
            public short wNumberingTab;
            public short wBorderSpace;
            public short wBorderWidth;
            public short wBorders;
        }

        private class RichEditOle
        {
            private MyExtRichTextBox _richEdit;
            private IRichEditOle _RichEditOle;
            public const int EM_GETOLEINTERFACE = 0x43c;
            public const int WM_USER = 0x400;

            public RichEditOle(MyExtRichTextBox richEdit)
            {
                this._richEdit = richEdit;
            }

            [DllImport("ole32.dll", PreserveSig=false)]
            internal static extern int CreateILockBytesOnHGlobal(IntPtr hGlobal, bool fDeleteOnRelease, out ILockBytes ppLkbyt);
            public void InsertControl(Control control)
            {
                if (control != null)
                {
                    ILockBytes pLockBytes;
                    IStorage pStorage;
                    IOleClientSite pOleClientSite;
                    Guid guid = Marshal.GenerateGuidForType(control.GetType());
                    CreateILockBytesOnHGlobal(IntPtr.Zero, true, out pLockBytes);
                    StgCreateDocfileOnILockBytes(pLockBytes, 0x1012, 0, out pStorage);
                    this.IRichEditOle.GetClientSite(out pOleClientSite);
                    REOBJECT reoObject = new REOBJECT();
                    reoObject.cp = this._richEdit.SelectionStart;
                    reoObject.clsid = guid;
                    reoObject.pstg = pStorage;
                    reoObject.poleobj = Marshal.GetIUnknownForObject(control);
                    reoObject.polesite = pOleClientSite;
                    reoObject.dvAspect = 1;
                    reoObject.dwFlags = 2;
                    try
                    {
                        reoObject.dwUser = Convert.ToUInt32((control as MyPicture).Tag);
                    }
                    catch
                    {
                    }
                    this.IRichEditOle.InsertObject(reoObject);
                    Marshal.ReleaseComObject(pLockBytes);
                    Marshal.ReleaseComObject(pOleClientSite);
                    Marshal.ReleaseComObject(pStorage);
                }
            }

            public bool InsertImageFromFile(string strFilename)
            {
                ILockBytes pLockBytes;
                IStorage pStorage;
                IOleClientSite pOleClientSite;
                object pOleObjectOut;
                CreateILockBytesOnHGlobal(IntPtr.Zero, true, out pLockBytes);
                StgCreateDocfileOnILockBytes(pLockBytes, 0x1012, 0, out pStorage);
                this.IRichEditOle.GetClientSite(out pOleClientSite);
                FORMATETC formatEtc = new FORMATETC();
                formatEtc.cfFormat = (CLIPFORMAT) 0;
                formatEtc.ptd = IntPtr.Zero;
                formatEtc.dwAspect = DVASPECT.DVASPECT_CONTENT;
                formatEtc.lindex = -1;
                formatEtc.tymed = TYMED.TYMED_NULL;
                Guid IID_IOleObject = new Guid("{00000112-0000-0000-C000-000000000046}");
                Guid CLSID_NULL = new Guid("{00000000-0000-0000-0000-000000000000}");
                int hr = MyExtRichTextBox.OleCreateFromFile(ref CLSID_NULL, strFilename, ref IID_IOleObject, 1, ref formatEtc, pOleClientSite, pStorage, out pOleObjectOut);
                if (pOleObjectOut == null)
                {
                    Marshal.ReleaseComObject(pLockBytes);
                    Marshal.ReleaseComObject(pOleClientSite);
                    Marshal.ReleaseComObject(pStorage);
                    return false;
                }
                IOleObject pOleObject = (IOleObject) pOleObjectOut;
                Guid guid = new Guid();
                pOleObject.GetUserClassID(ref guid);
                MyExtRichTextBox.OleSetContainedObject(pOleObject, true);
                REOBJECT reoObject = new REOBJECT();
                reoObject.cp = this._richEdit.TextLength;
                reoObject.clsid = guid;
                reoObject.pstg = pStorage;
                reoObject.poleobj = Marshal.GetIUnknownForObject(pOleObject);
                reoObject.polesite = pOleClientSite;
                reoObject.dvAspect = 1;
                reoObject.dwFlags = 2;
                reoObject.dwUser = 0;
                this.IRichEditOle.InsertObject(reoObject);
                Marshal.ReleaseComObject(pLockBytes);
                Marshal.ReleaseComObject(pOleClientSite);
                Marshal.ReleaseComObject(pStorage);
                Marshal.ReleaseComObject(pOleObject);
                return true;
            }

            public void InsertMyDataObject(myDataObject mdo)
            {
                if (mdo != null)
                {
                    ILockBytes pLockBytes;
                    IStorage pStorage;
                    IOleClientSite pOleClientSite;
                    object pOleObject;
                    int sc = CreateILockBytesOnHGlobal(IntPtr.Zero, true, out pLockBytes);
                    sc = StgCreateDocfileOnILockBytes(pLockBytes, 0x1012, 0, out pStorage);
                    this.IRichEditOle.GetClientSite(out pOleClientSite);
                    Guid guid = Marshal.GenerateGuidForType(mdo.GetType());
                    Guid IID_IOleObject = new Guid("{00000112-0000-0000-C000-000000000046}");
                    Guid IID_IDataObject = new Guid("{0000010e-0000-0000-C000-000000000046}");
                    Guid IID_IUnknown = new Guid("{00000000-0000-0000-C000-000000000046}");
                    int hr = MyExtRichTextBox.OleCreateStaticFromData(mdo, ref IID_IOleObject, 2, ref mdo.mpFormatetc, pOleClientSite, pStorage, out pOleObject);
                    if (pOleObject != null)
                    {
                        MyExtRichTextBox.OleSetContainedObject(pOleObject, true);
                        REOBJECT reoObject = new REOBJECT();
                        reoObject.cp = this._richEdit.TextLength;
                        reoObject.clsid = guid;
                        reoObject.pstg = pStorage;
                        reoObject.poleobj = Marshal.GetIUnknownForObject(pOleObject);
                        reoObject.polesite = pOleClientSite;
                        reoObject.dvAspect = 1;
                        reoObject.dwFlags = 2;
                        reoObject.dwUser = 0;
                        this.IRichEditOle.InsertObject(reoObject);
                        Marshal.ReleaseComObject(pLockBytes);
                        Marshal.ReleaseComObject(pOleClientSite);
                        Marshal.ReleaseComObject(pStorage);
                        Marshal.ReleaseComObject(pOleObject);
                    }
                }
            }

            public void InsertOleObject(IOleObject oleObject)
            {
                if (oleObject != null)
                {
                    ILockBytes pLockBytes;
                    IStorage pStorage;
                    IOleClientSite pOleClientSite;
                    CreateILockBytesOnHGlobal(IntPtr.Zero, true, out pLockBytes);
                    StgCreateDocfileOnILockBytes(pLockBytes, 0x1012, 0, out pStorage);
                    this.IRichEditOle.GetClientSite(out pOleClientSite);
                    Guid guid = new Guid();
                    oleObject.GetUserClassID(ref guid);
                    MyExtRichTextBox.OleSetContainedObject(oleObject, true);
                    REOBJECT reoObject = new REOBJECT();
                    reoObject.cp = this._richEdit.TextLength;
                    reoObject.clsid = guid;
                    reoObject.pstg = pStorage;
                    reoObject.poleobj = Marshal.GetIUnknownForObject(oleObject);
                    reoObject.polesite = pOleClientSite;
                    reoObject.dvAspect = 1;
                    reoObject.dwFlags = 2;
                    this.IRichEditOle.InsertObject(reoObject);
                    Marshal.ReleaseComObject(pLockBytes);
                    Marshal.ReleaseComObject(pOleClientSite);
                    Marshal.ReleaseComObject(pStorage);
                }
            }

            [DllImport("ole32.dll")]
            private static extern int StgCreateDocfileOnILockBytes(ILockBytes plkbyt, uint grfMode, uint reserved, out IStorage ppstgOpen);
            public void UpdateObjects()
            {
                int k = this.IRichEditOle.GetObjectCount();
                for (int i = 0; i < k; i++)
                {
                    REOBJECT reoObject = new REOBJECT();
                    this.IRichEditOle.GetObject(i, reoObject, GETOBJECTOPTIONS.REO_GETOBJ_ALL_INTERFACES);
                    if (reoObject.dwUser == 1)
                    {
                        Point pt = this._richEdit.GetPositionFromCharIndex(reoObject.cp);
                        Rectangle rect = new Rectangle(pt, reoObject.sizel);
                        this._richEdit.Invalidate(rect, false);
                    }
                }
            }

            private IRichEditOle IRichEditOle
            {
                get
                {
                    if (this._RichEditOle == null)
                    {
                        this._RichEditOle = MyExtRichTextBox.SendMessage(this._richEdit.Handle, 0x43c, 0);
                    }
                    return this._RichEditOle;
                }
            }
        }

        [StructLayout(LayoutKind.Sequential, Size=1)]
        private struct RtfColorDef
        {
            public const string Black = @"\red0\green0\blue0";
            public const string Maroon = @"\red128\green0\blue0";
            public const string Green = @"\red0\green128\blue0";
            public const string Olive = @"\red128\green128\blue0";
            public const string Navy = @"\red0\green0\blue128";
            public const string Purple = @"\red128\green0\blue128";
            public const string Teal = @"\red0\green128\blue128";
            public const string Gray = @"\red128\green128\blue128";
            public const string Silver = @"\red192\green192\blue192";
            public const string Red = @"\red255\green0\blue0";
            public const string Lime = @"\red0\green255\blue0";
            public const string Yellow = @"\red255\green255\blue0";
            public const string Blue = @"\red0\green0\blue255";
            public const string Fuchsia = @"\red255\green0\blue255";
            public const string Aqua = @"\red0\green255\blue255";
            public const string White = @"\red255\green255\blue255";
        }

        [StructLayout(LayoutKind.Sequential, Size=1)]
        private struct RtfFontFamilyDef
        {
            public const string Unknown = @"\fnil";
            public const string Roman = @"\froman";
            public const string Swiss = @"\fswiss";
            public const string Modern = @"\fmodern";
            public const string Script = @"\fscript";
            public const string Decor = @"\fdecor";
            public const string Technical = @"\ftech";
            public const string BiDirect = @"\fbidi";
        }
    }
}

